// Copyright (c) 2012, yuno. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
//    this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of contributors
//    may be used to endorse or promote products derived from this software
//    without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
package sugarmintcandy.widgetwindow;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Parcelable;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.AdapterView;
import android.widget.FrameLayout;
import android.widget.GridView;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TabHost;
import android.widget.TextView;

public class ColorPicker extends FrameLayout implements
	ColorCircle.OnChangeListener, VerticalBrightnessBar.OnChangeListener,
	VerticalAlphaBar.OnChangeListener, HorizontalColorBar.OnChangeListener,
	View.OnClickListener, AdapterView.OnItemClickListener {
    private ColorPickerBackgroundView mBackground;
    private TabHost mTabHost;

    private ColorCircle mHsvColorCircle;
    private VerticalBrightnessBar mHsvBrightnessBar;
    private VerticalAlphaBar mHsvAlphaBar;

    private HorizontalColorBar mRgbRedBar;
    private HorizontalColorBar mRgbGreenBar;
    private HorizontalColorBar mRgbBlueBar;
    private HorizontalColorBar mRgbAlphaBar;
    private ImageButton mRgbRedDownButton;
    private ImageButton mRgbGreenDownButton;
    private ImageButton mRgbBlueDownButton;
    private ImageButton mRgbAlphaDownButton;
    private ImageButton mRgbRedUpButton;
    private ImageButton mRgbGreenUpButton;
    private ImageButton mRgbBlueUpButton;
    private ImageButton mRgbAlphaUpButton;
    private TextView mRgbRedTextView;
    private TextView mRgbGreenTextView;
    private TextView mRgbBlueTextView;
    private TextView mRgbAlphaTextView;
    private ColorGridAdapter mRecentGridAdapter;
    private GridView mRecentGrid;
    private View mRecentClearButton;

    private MainDatabase mDatabase;
    private float mRed;
    private float mGreen;
    private float mBlue;
    private float mAlpha;
    private float[] mHSV;

    public ColorPicker(Context context) {
	super(context);

	MainApplication app = (MainApplication) context.getApplicationContext();
	mDatabase = app.getDatabase();
	mRed = 1;
	mGreen = 1;
	mBlue = 1;
	mAlpha = 1;
	mHSV = new float[3];
	Color.colorToHSV(-1, mHSV);

	LayoutInflater inflater = LayoutInflater.from(context);
	inflater.inflate(R.layout.color_picker, this);

	mTabHost = (TabHost) findViewById(android.R.id.tabhost);
	mTabHost.setup();
	addTab("HSV", R.string.hsv, R.drawable.hsv, R.id.hsv_pane);
	addTab("RGB", R.string.rgb, R.drawable.rgb, R.id.rgb_pane);
	addTab("Recent", R.string.recent_colors, R.drawable.recent_colors,
		R.id.recent_pane);
	mBackground = (ColorPickerBackgroundView) findViewById(android.R.id.tabcontent);

	mHsvColorCircle = (ColorCircle) findViewById(R.id.hsv_color_circle);
	mHsvColorCircle.setOnChangeListener(this);
	mHsvBrightnessBar = (VerticalBrightnessBar) findViewById(R.id.hsv_brightness_bar);
	mHsvBrightnessBar.setOnChangeListener(this);
	mHsvAlphaBar = (VerticalAlphaBar) findViewById(R.id.hsv_alpha_bar);
	mHsvAlphaBar.setOnChangeListener(this);

	mRgbRedBar = (HorizontalColorBar) findViewById(R.id.rgb_red_bar);
	mRgbRedBar.setBarColors(0xff000000, 0xffff0000);
	mRgbRedBar.setOnChangeListener(this);
	mRgbRedDownButton = (ImageButton) findViewById(R.id.rgb_red_down_button);
	mRgbRedDownButton.setImageDrawable(new LeftArrowDrawable());
	mRgbRedDownButton.setOnClickListener(this);
	mRgbRedUpButton = (ImageButton) findViewById(R.id.rgb_red_up_button);
	mRgbRedUpButton.setImageDrawable(new RightArrowDrawable());
	mRgbRedUpButton.setOnClickListener(this);
	mRgbRedTextView = (TextView) findViewById(R.id.rgb_red_text);

	mRgbGreenBar = (HorizontalColorBar) findViewById(R.id.rgb_green_bar);
	mRgbGreenBar.setBarColors(0xff000000, 0xff00ff00);
	mRgbGreenBar.setOnChangeListener(this);
	mRgbGreenDownButton = (ImageButton) findViewById(R.id.rgb_green_down_button);
	mRgbGreenDownButton.setImageDrawable(new LeftArrowDrawable());
	mRgbGreenDownButton.setOnClickListener(this);
	mRgbGreenUpButton = (ImageButton) findViewById(R.id.rgb_green_up_button);
	mRgbGreenUpButton.setImageDrawable(new RightArrowDrawable());
	mRgbGreenUpButton.setOnClickListener(this);
	mRgbGreenTextView = (TextView) findViewById(R.id.rgb_green_text);

	mRgbBlueBar = (HorizontalColorBar) findViewById(R.id.rgb_blue_bar);
	mRgbBlueBar.setBarColors(0xff000000, 0xff0000ff);
	mRgbBlueBar.setOnChangeListener(this);
	mRgbBlueDownButton = (ImageButton) findViewById(R.id.rgb_blue_down_button);
	mRgbBlueDownButton.setImageDrawable(new LeftArrowDrawable());
	mRgbBlueDownButton.setOnClickListener(this);
	mRgbBlueUpButton = (ImageButton) findViewById(R.id.rgb_blue_up_button);
	mRgbBlueUpButton.setImageDrawable(new RightArrowDrawable());
	mRgbBlueUpButton.setOnClickListener(this);
	mRgbBlueTextView = (TextView) findViewById(R.id.rgb_blue_text);

	mRgbAlphaBar = (HorizontalColorBar) findViewById(R.id.rgb_alpha_bar);
	mRgbAlphaBar.setBarColors(0x00ffffff, 0xffffffff);
	mRgbAlphaBar.setOnChangeListener(this);
	mRgbAlphaDownButton = (ImageButton) findViewById(R.id.rgb_alpha_down_button);
	mRgbAlphaDownButton.setImageDrawable(new LeftArrowDrawable());
	mRgbAlphaDownButton.setOnClickListener(this);
	mRgbAlphaUpButton = (ImageButton) findViewById(R.id.rgb_alpha_up_button);
	mRgbAlphaUpButton.setImageDrawable(new RightArrowDrawable());
	mRgbAlphaUpButton.setOnClickListener(this);
	mRgbAlphaTextView = (TextView) findViewById(R.id.rgb_alpha_text);

	mRecentGridAdapter = new ColorGridAdapter();
	mRecentGrid = (GridView) findViewById(R.id.recent_grid);
	mRecentGrid.setAdapter(mRecentGridAdapter);
	mRecentGrid.setOnItemClickListener(this);
	mRecentClearButton = findViewById(R.id.recent_clear_button);
	mRecentClearButton.setOnClickListener(this);
    }

    private void addTab(String tag, int title, int icon, int content) {
	TabHost.TabSpec spec = mTabHost.newTabSpec(tag);
	spec.setContent(content);
	if (ApiHelper.SDK_INT >= 11) {
	    LayoutInflater inflater = LayoutInflater.from(getContext());
	    View view = inflater.inflate(R.layout.tab_indicator_holo,
		    mTabHost.getTabWidget(), false);
	    ImageView iconView = (ImageView) view.findViewById(R.id.icon);
	    iconView.setImageResource(icon);
	    TextView titleView = (TextView) view.findViewById(R.id.title);
	    titleView.setText(title);
	    ApiHelper.setIndicator(spec, view);
	} else {
	    Resources res = getResources();
	    spec.setIndicator(res.getString(title), res.getDrawable(icon));
	}
	mTabHost.addTab(spec);
    }

    public void prepare() {
	mTabHost.setCurrentTab(0);
	mRecentGridAdapter.setColors(mDatabase.getRecentColors());
    }

    @Override
    protected Parcelable onSaveInstanceState() {
	Bundle bundle = new Bundle();
	bundle.putParcelable("super", super.onSaveInstanceState());
	bundle.putFloat("mRed", mRed);
	bundle.putFloat("mGreen", mGreen);
	bundle.putFloat("mBlue", mBlue);
	bundle.putFloat("mAlpha", mAlpha);
	bundle.putFloatArray("mHSV", mHSV);
	return bundle;
    }

    @Override
    protected void onRestoreInstanceState(Parcelable state) {
	Bundle bundle = (Bundle) state;
	super.onRestoreInstanceState(bundle.getParcelable("super"));
	mRed = bundle.getFloat("mRed");
	mGreen = bundle.getFloat("mGreen");
	mBlue = bundle.getFloat("mBlue");
	mAlpha = bundle.getFloat("mAlpha");
	mHSV = bundle.getFloatArray("mHSV");
	updateViews();
    }

    public int getColor() {
	int red = Math.round(mRed * 255f);
	int green = Math.round(mGreen * 255f);
	int blue = Math.round(mBlue * 255f);
	int alpha = Math.round(mAlpha * 255f);
	return (alpha << 24) | (red << 16) | (green << 8) | blue;
    }

    public void setColor(int color) {
	Color.colorToHSV(color, mHSV);
	mAlpha = (color >>> 24) / 255f;
	mRed = ((color >> 16) & 255) / 255f;
	mGreen = ((color >> 8) & 255) / 255f;
	mBlue = (color & 255) / 255f;
	updateViews();
    }

    private void setRGBfromHSV() {
	int color = Color.HSVToColor(mHSV);
	mRed = ((color >> 16) & 255) / 255f;
	mGreen = ((color >> 8) & 255) / 255f;
	mBlue = (color & 255) / 255f;
    }

    private void setHSVfromRGB() {
	Color.colorToHSV(getColor(), mHSV);
    }

    private void updateViews() {
	mBackground.setColor(getColor());
	mHsvColorCircle.setHSV(mHSV);
	mHsvBrightnessBar.setHSV(mHSV);
	mHsvAlphaBar.setHSV(mHSV);
	mHsvAlphaBar.setAlphaValue(mAlpha);
	mRgbRedBar.setValue(mRed);
	mRgbGreenBar.setValue(mGreen);
	mRgbBlueBar.setValue(mBlue);
	mRgbAlphaBar.setValue(mAlpha);
	mRgbRedTextView.setText(String.valueOf(Math.round(mRed * 255f)));
	mRgbGreenTextView.setText(String.valueOf(Math.round(mGreen * 255f)));
	mRgbBlueTextView.setText(String.valueOf(Math.round(mBlue * 255f)));
	mRgbAlphaTextView.setText(String.valueOf(Math.round(mAlpha * 255f)));
    }

    @Override
    public void onChange(ColorCircle view) {
	float[] hsv1 = mHsvColorCircle.getHSV();
	mHSV[0] = hsv1[0];
	mHSV[1] = hsv1[1];
	setRGBfromHSV();
	updateViews();
    }

    @Override
    public void onChange(VerticalBrightnessBar view) {
	float[] hsv = mHsvBrightnessBar.getHSV();
	mHSV[2] = hsv[2];
	setRGBfromHSV();
	updateViews();
    }

    @Override
    public void onChange(VerticalAlphaBar view) {
	mAlpha = mHsvAlphaBar.getAlphaValue();
	updateViews();
    }

    @Override
    public void onChange(HorizontalColorBar view) {
	if (view == mRgbAlphaBar) {
	    mAlpha = mRgbAlphaBar.getValue();
	} else {
	    mRed = mRgbRedBar.getValue();
	    mGreen = mRgbGreenBar.getValue();
	    mBlue = mRgbBlueBar.getValue();
	    setHSVfromRGB();
	}
	updateViews();
    }

    @Override
    public void onClick(View v) {
	switch (v.getId()) {
	case R.id.rgb_red_down_button:
	    mRed = Math.max(0, (Math.round(mRed * 255f) - 1) / 255f);
	    setHSVfromRGB();
	    updateViews();
	    break;
	case R.id.rgb_red_up_button:
	    mRed = Math.min(1, (Math.round(mRed * 255f) + 1) / 255f);
	    setHSVfromRGB();
	    updateViews();
	    break;
	case R.id.rgb_green_down_button:
	    mGreen = Math.max(0, (Math.round(mGreen * 255f) - 1) / 255f);
	    setHSVfromRGB();
	    updateViews();
	    break;
	case R.id.rgb_green_up_button:
	    mGreen = Math.min(1, (Math.round(mGreen * 255f) + 1) / 255f);
	    setHSVfromRGB();
	    updateViews();
	    break;
	case R.id.rgb_blue_down_button:
	    mBlue = Math.max(0, (Math.round(mBlue * 255f) - 1) / 255f);
	    setHSVfromRGB();
	    updateViews();
	    break;
	case R.id.rgb_blue_up_button:
	    mBlue = Math.min(1, (Math.round(mBlue * 255f) + 1) / 255f);
	    setHSVfromRGB();
	    updateViews();
	    break;
	case R.id.rgb_alpha_down_button:
	    mAlpha = Math.max(0, (Math.round(mAlpha * 255f) - 1) / 255f);
	    updateViews();
	    break;
	case R.id.rgb_alpha_up_button:
	    mAlpha = Math.min(1, (Math.round(mAlpha * 255f) + 1) / 255f);
	    updateViews();
	    break;
	case R.id.recent_clear_button:
	    mDatabase.deleteRecentColors();
	    mRecentGridAdapter.setColors(new int[0]);
	    break;
	}
    }

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position,
	    long id) {
	if (view instanceof ColorGridCellView) {
	    int color = ((ColorGridCellView) view).getColor();
	    Color.colorToHSV(color, mHSV);
	    mRed = ((color >> 16) & 255) / 255f;
	    mGreen = ((color >> 8) & 255) / 255f;
	    mBlue = (color & 255) / 255f;
	    updateViews();
	}
    }
}
